<template>
  <component
    v-bind="binds"
    :defaultExpandAll="attrs.defaultExpandAll || true"
    :is="getComponents(attrs.type)"
    :options="optionList"
    :tree-data="optionList"
    @check="change"
    @change="change"
    v-if="attrs.type === 'Cascader'"
  >
  </component>

  <div v-else-if="attrs.slotName"><slot :name="attrs.slotName" /></div>
  <component
    v-else
    v-bind="binds"
    :defaultExpandAll="attrs.defaultExpandAll || true"
    :is="getComponents(attrs.type)"
    :options="optionList"
    :tree-data="optionList"
    @check="change"
    @change="change"
  >
    <div v-if="attrs.render" v-html="attrs.render()"></div>
  </component>
  <!-- <div>{{attrs.value}}</div> -->
</template>
<script setup>
import * as Eles from "ant-design-vue";
console.log(Eles, "Eles");
const props = defineProps({
  attrs: {
    type: Object,
    default: () => {
      return {};
    },
  },
});

const emit = defineEmits();

/**
 * 计算属性，用于绑定除了options之外的所有props到组件的内部属性。
 * 这样做是为了在组件内部使用props时，避免直接操作原始props对象，以确保数据的隔离和纯净。
 * 同时，也避免了在模板中因为options属性的存在而需要进行额外的处理。
 *
 * @returns {Object} 返回一个对象，包含了除了options之外的所有props属性。
 */
const binds = computed(() => {
  // 创建一个对象并复制props.attrs的所有属性
  const obj = { ...props.attrs };
  // 删除复制对象中的options属性，因为这个属性不需要在内部绑定
  delete obj.options;
  // 返回复制并修改后的对象
  return obj;
});
/**
 * 使用计算属性创建一个函数，该函数根据传入的类型返回对应元素。
 * 这种做法提供了动态访问Eles对象中特定类型元素的能力，而无需直接暴露Eles对象的内部结构。
 *
 * @returns {Function} 返回一个函数，该函数接受一个类型参数，并返回Eles对象中对应类型的元素。
 */
const getComponents = computed(() => (type) => {
  if (!type) return;
  if (type === "TextArea") {
    const { TextArea } = Eles["Input"];
    return TextArea;
  }

  return Eles[type];
});

// 使用ref创建一个空数组，用于存储选项列表
const optionList = ref([]);
/**
 * 异步获取选项数据，并根据数据类型处理成相应的格式
 * 主要用于处理Select组件的选项加载
 *
 * @returns {void}
 */
const getOptions = async () => {
  // 从props中获取attrs中的options属性，这通常是由父组件传递过来的选项数据或获取选项的数据函数
  const options = props.attrs.options;
  // 初始化一个空数组，用于存储处理后的选项数据
  let list = [];

  const dep = (arr, children, label, value, labelKey, valueKey) => {
    return arr.map((a) => {
      const o = {};
      o[labelKey || "label"] = a[label];
      o[valueKey || "value"] = a[value];
      if (a[children] && a[children].length) {
        o["children"] = dep(
          a[children],
          children,
          label,
          value,
          labelKey,
          valueKey
        );
      }
      return o;
    });
  };

  // 判断当前组件的类型是否为"Select"，这是为了确保后续的操作适用于Select组件
  if (
    props.attrs.type === "Select" ||
    props.attrs.type === "CheckboxGroup" ||
    props.attrs.type === "RadioGroup" ||
    props.attrs.type === "Tree" ||
    props.attrs.type === "TreeSelect" ||
    props.attrs.type === "Cascader"
  ) {
    // 判断options是否为函数，如果是，则调用该函数获取选项数据
    if (options && options instanceof Function) {
      // 调用options函数，并等待其返回结果
      const { code, data } = await options();

      // 判断返回结果的code是否符合预期，通常是判断是否请求成功
      if (code === rescf.codeVal) {
        // 如果请求成功，则处理数据，将其转换为Select组件需要的格式

        const D = data.list ? data.list : data;
        list = D.map((a) => {
          // 创建一个对象，包含选项的label和value属性
          const o = {};
          // 设置选项的显示文本，优先使用props中指定的optionsLabel，如果未指定，则使用"label"作为默认值
          o[props.attrs.optionsProps?.labelKey || "label"] =
            a[props.attrs.optionsProps?.label || "label"];
          // 设置选项的值，优先使用props中指定的optionValue，如果未指定，则使用"value"作为默认值
          o[props.attrs.optionsProps?.valueKey || "value"] =
            a[props.attrs.optionsProps?.value || "value"];

          if (
            props.attrs.optionsProps &&
            a[props.attrs.optionsProps.children]
          ) {
            o[props.attrs.optionsProps.children] = dep(
              a[props.attrs.optionsProps.children],
              props.attrs.optionsProps.children,
              props.attrs.optionsProps.label,
              props.attrs.optionsProps.value,
              props.attrs.optionsProps.labelKey,
              props.attrs.optionsProps.valueKey
            );
          }
          // 返回处理后的选项对象
          return o;
        });
        // 将处理后的选项数据赋值给optionList
        optionList.value = list;
        console.log(list, "=====================");
        if (props.attrs.autoSelected) {
          emit("autoSelected", props.attrs, optionList.value);
        }
      }
    } else {
      // 如果options不是函数，则直接将options赋值给optionList
      optionList.value = options.map((a) => {
        // 创建一个对象，包含选项的label和value属性
        const o = {};
        // 设置选项的显示文本，优先使用props中指定的optionsLabel，如果未指定，则使用"label"作为默认值
        o[props.attrs.optionsProps?.labelKey || "label"] =
          a[props.attrs.optionsProps?.label || "label"];
        // 设置选项的值，优先使用props中指定的optionValue，如果未指定，则使用"value"作为默认值
        o[props.attrs.optionsProps?.valueKey || "value"] =
          a[props.attrs.optionsProps?.value || "value"];

        if (props.attrs.optionsProps && a[props.attrs.optionsProps.children]) {
          o[props.attrs.optionsProps.children] = dep(
            a[props.attrs.optionsProps.children],
            props.attrs.optionsProps.children,
            props.attrs.optionsProps.label,
            props.attrs.optionsProps.value,
            props.attrs.optionsProps.labelKey,
            props.attrs.optionsProps.valueKey
          );
        }
        // 返回处理后的选项对象
        return o;
      });
      if (props.attrs.autoSelected) {
        emit("autoSelected", props.attrs, optionList.value);
      }
    }
  }
};

// 调用getOptions函数，用于初始化选项列表
getOptions();

const change = (val, val2) => {
  // 触发父组件的change事件，并将处理后的值作为参数传递
  if (val && val.target) {
    val = val.target.value;
  }

  if (props.attrs.type === "Upload") {
    const { file, fileList } = val;
    if (file.status === "done") {
      let v = fileList.map((a) => a.response && a.response.data);
      emit(
        "elChange",
        {
          field: props.attrs.field,
          value: v,
        },
        val2
      );
    }
  } else {
    emit(
      "elChange",
      {
        field: props.attrs.field,
        value: val,
      },
      val2
    );
  }
  if (props.attrs.call) {
    props.attrs.call(val, val2);
  }
};
</script>
